package com.mingserve.common.core.utils;

import com.mingserve.common.core.exception.UtilException;

import java.net.*;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.function.Predicate;

/**
 * 网络工具类
 *
 * @author lvwshuai
 * @date 2025-05-30
 */
public class NetUtil {
    private static final String DEFAULT_MAC_SEPARATOR = "-";

    // 私有构造防止实例化
    private NetUtil() {}

    /**
     * 获取本地IP地址(第一个)
     *
     * @return
     */
    public static InetAddress getLocalhost()
    {
        // 优先获取非回环、IPv4、非站点本地的地址
        LinkedHashSet<InetAddress> localAddressList = localAddressList((address) -> !address.isLoopbackAddress() && address instanceof Inet4Address);
        if (StringUtils.isNotEmpty(localAddressList)) {
            InetAddress firstAddress = null;

            for (InetAddress inetAddress : localAddressList) {
                if (!inetAddress.isSiteLocalAddress()) {
                    return inetAddress;
                }

                if (firstAddress == null) {
                    firstAddress = inetAddress;
                }
            }
            if (firstAddress != null) {
                return firstAddress;
            }
        }
        try {
            return InetAddress.getLocalHost();
        } catch (UnknownHostException var4) {
            return null;
        }
    }
    public static LinkedHashSet<InetAddress> localAddressList(Predicate<InetAddress> addressFilter)
    {
        return localAddressList(null, addressFilter);
    }

    /**
     * 获取本地IP地址
     *
     * @param networkInterfaceFilter 网络接口过滤器，用于过滤不需要的接口
     * @param addressFilter          地址过滤器，用于过滤不需要的IP地址
     * @return
     */
    public static LinkedHashSet<InetAddress> localAddressList( Predicate<NetworkInterface> networkInterfaceFilter, Predicate<InetAddress> addressFilter)
    {

        Enumeration<NetworkInterface> networkInterfaces;
        try {
            networkInterfaces = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            throw new UtilException(e);
        }

        LinkedHashSet<InetAddress> ipSet = new LinkedHashSet<>();

        while (networkInterfaces.hasMoreElements()) {
            NetworkInterface networkInterface = networkInterfaces.nextElement();

            // 应用网络接口过滤器
            if (networkInterfaceFilter != null && !networkInterfaceFilter.test(networkInterface)) {
                continue;
            }

            Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();

                //排除LoopbackAddress、SiteLocalAddress、LinkLocalAddress、MulticastAddress类型的IP地址
                if (!address.isLoopbackAddress() /*&& !inetAddr.isSiteLocalAddress()*/
                        && !address.isLinkLocalAddress()
                        && !address.isMulticastAddress()) {

                    // 应用地址过滤器
                    if (addressFilter == null || addressFilter.test(address)) {
                        ipSet.add(address);
                    }
                }
            }
        }

        return ipSet;
    }
    /**
     * 获取Mac地址（取第一个有IP的）
     *
     * @return
     */
    public static String getLocalMacAddress()
    {
        return getMacAddress(getLocalhost());
    }

    /**
     * 获取指定IP对应的MAC地址
     *
     * @param inetAddress
     * @return
     */
    public static String getMacAddress(InetAddress inetAddress)
    {
        return getMacAddress(inetAddress, DEFAULT_MAC_SEPARATOR);
    }

    /**
     * 获取指定IP对应的MAC地址，使用指定分隔符
     *
     * @param inetAddress
     * @param separator
     */
    public static String getMacAddress(InetAddress inetAddress, String separator)
    {
        if (null == inetAddress) {
            return null;
        }
        byte[] mac = getHardwareAddress(inetAddress);
        if (mac == null) {
            return null;
        }
        return formatMacAddress(mac, separator);
    }

    /**
     * 格式化MAC地址
     *
     * @param mac       MAC地址
     * @param separator 分隔符，如果为null，则不分隔
     * @return
     */
    private static String formatMacAddress(byte[] mac, String separator)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) {
                sb.append(separator);
            }
            sb.append(String.format("%02x", mac[i] & 0xff));
        }
        return sb.toString();
    }

    /**
     * 获取MAC地址
     *
     * @param inetAddress
     * @return
     */
    public static byte[] getHardwareAddress(InetAddress inetAddress)
    {
        if (null == inetAddress) {
            return null;
        } else {
            try {
                NetworkInterface networkInterface = NetworkInterface.getByInetAddress(inetAddress);
                return null != networkInterface ? networkInterface.getHardwareAddress() : null;
            } catch (SocketException e) {
                throw new UtilException("Failed to get hardware address", e);
            }
        }
    }
}
